#include "Socket.h"
#include "SocketOps.h"
#include "SocketMgrLinux.h"

Socket::Socket(SOCKET sFd,int iSendBufferSize,int iRecvBufferSize) : m_bConnected(false),m_bDeleted(false)
{
    m_sSocket = sFd;
    m_kSendBuffer.Allocate(iSendBufferSize);
    m_kRecvBuffer.Allocate(iRecvBufferSize);

    if(m_sSocket == 0)
    {
        m_sSocket = SocketOps::CreateTCPFileDescriptor();
    }
}

Socket::~Socket()
{
    printf("Socket [%d] ~Socket.\n",m_sSocket);
}
void Socket::SetSocketMgr(SocketMgr* pkMgr)
{
    m_pkMgr = pkMgr;
}
void Socket::SetServerAddr(sockaddr_in& kAddr)
{
    m_kServer = kAddr;
}
bool Socket::Connect(const char * pcAddress,int iPort)
{
    struct hostent * ci = gethostbyname(pcAddress);
    if(ci == 0)
    {
        return false;
    }

    m_kClient.sin_family = ci->h_addrtype;
    m_kClient.sin_port = ntohs((u_short)iPort);
    memcpy(&m_kClient.sin_addr.s_addr, ci->h_addr_list[0], ci->h_length);

    SocketOps::Blocking(m_sSocket);
    if(connect(m_sSocket,(const sockaddr*)&m_kClient, sizeof(m_kClient)) == -1)
    {
        return false;
    }

    _OnConnect();

    OnConnect();
    return true;
}

void Socket::Accept(sockaddr_in * pkAddress)
{
    memcpy(&m_kClient, pkAddress, sizeof(*pkAddress));
    _OnConnect();

    OnAccept();
}

void Socket::_OnConnect()
{
    SocketOps::Nonblocking(m_sSocket);
    SocketOps::DisableBuffering(m_sSocket);
    /*	SocketOps::SetRecvBufferSize(m_fd, m_writeBufferSize);
    SocketOps::SetSendBufferSize(m_fd, m_writeBufferSize);*/
    m_bConnected = true;

    m_pkMgr->AddSocket(this);

}

bool Socket::Send(const uint8 * pBytes,int iSize)
{
    bool rv = BurstSend(pBytes, iSize);
    if(rv)
    {
       PostEvent(EPOLLOUT);
    }
    return rv;
}

bool Socket::BurstSend(const uint8 * pBytes,int iSize)
{
    return m_kSendBuffer.WriteBuffer(pBytes, iSize);
}

std::string Socket::GetRemoteIP()
{
    char* pcIP = (char*)inet_ntoa(m_kClient.sin_addr);
    if(pcIP != NULL)
    {
        return std::string(pcIP);
    }
    return std::string("noip");
}

void Socket::Disconnect()
{
    m_bConnected = false;
    if(!m_pkMgr)
    {
        return;
    }
    m_pkMgr->RemoveSocket(this);

    SocketOps::CloseSocket(m_sSocket);

    OnDisconnect();

    if(!m_bDeleted)
    {
        Delete();
    }
}

void Socket::Delete()
{
    if(m_bDeleted)
    {
        return;
    }
    m_bDeleted = true;

    if(m_bConnected)
    {
        Disconnect();
    }
}

void Socket::PostEvent(int iEvents)
{
    int iEpollFd = m_pkMgr->GetEpollFd();

    struct epoll_event ev;
    memset(&ev, 0, sizeof(epoll_event));
    ev.data.ptr = this;
    ev.events = iEvents | EPOLLET;

    if(epoll_ctl(iEpollFd, EPOLL_CTL_MOD,m_sSocket, &ev))
    {
        printf("epoll", "Could not post event on fd %u\n", m_sSocket);
    }
}


void Socket::ReadCallback(int iLen)
{
    bool  bRet = m_kRecvBuffer.RecvData(m_sSocket);
    printf("read result:%d.\n",bRet);
    if(!bRet)
    {
        //PostEvent(EPOLLERR);
        Disconnect();
        return;
    }
    m_pkMgr->PushSocket(this);
}

void Socket::WriteCallback()
{
    bool bRet = m_kSendBuffer.SendData(m_sSocket);
    if(!bRet)
    {
        Disconnect();
    }
}

void Socket::OnAccept()
{
    HSock kSock((void*)m_sSocket,0);

    if(m_pkMgr && m_pkMgr->GetCall())
    {
        m_pkMgr->GetCall()->OnAccept(kSock,inet_ntoa(m_kServer.sin_addr),htons(m_kServer.sin_port));
    }
}
void Socket::OnConnect()
{
    HSock kSock((void*)m_sSocket,0);

    if(m_pkMgr && m_pkMgr->GetCall())
    {
        m_pkMgr->GetCall()->OnConnected(kSock,inet_ntoa(m_kServer.sin_addr),htons(m_kServer.sin_port));
    }
}
void Socket::OnRead()
{
    printf("Socket::OnRead().\n");
    HSock kSock((void*)m_sSocket,0);

    int iLen = 0;
    char buf[SOCKET_DATE_SIZE] = {};

    bool bRet = m_kRecvBuffer.ReadBuffer(&iLen,2);
    if(!bRet)
    {
        return;
    }
    printf("..data:%s.\n",buf);
    bRet = m_kRecvBuffer.ReadBuffer(buf,iLen);
    if(!bRet)
    {
        return;
    }
    if(m_pkMgr && m_pkMgr->GetCall())
    {
        m_pkMgr->GetCall()->OnRecv(kSock,buf,iLen);
    }
}
void Socket::OnDisconnect()
{
    HSock kSock((void*)m_sSocket,0);
    printf("Socket::OnDisConnect().\n");
    if(m_pkMgr && m_pkMgr->GetCall())
    {
        m_pkMgr->GetCall()->OnDisConnect(kSock);
    }
}
